from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from database import get_db
from models import Menu, User
from schemas import MenuCreate, MenuUpdate, MenuSchema, ResponseModel, PaginatedResponse
from api.deps import get_current_active_user, get_current_superuser

router = APIRouter()

def build_menu_tree(menus: List[Menu], parent_id: Optional[int] = None) -> List[MenuSchema]:
    """递归构建菜单树形结构"""
    tree = []
    
    for menu in menus:
        if menu.parent_id == parent_id:
            # 转换为schema对象
            menu_dict = {
                "id": menu.id,
                "name": menu.name,
                "path": menu.path,
                "component": menu.component,
                "redirect": menu.redirect,
                "always_show": menu.always_show,
                "hidden": menu.hidden,
                "title": menu.title,
                "icon": menu.icon,
                "no_cache": menu.no_cache,
                "breadcrumb": menu.breadcrumb,
                "parent_id": menu.parent_id,
                "permission_ids": menu.permission_ids,
                "permissions": menu.permissions,
                "sort_order": menu.sort_order,
                "created_at": menu.created_at,
                "updated_at": menu.updated_at
            }
            # 递归获取子菜单
            menu_dict["children"] = build_menu_tree(menus, menu.id)
            tree.append(menu_dict)
    
    # 按排序字段排序
    tree.sort(key=lambda x: x.get("sort_order", 0))
    return tree

@router.get("/tree", response_model=ResponseModel[List[MenuSchema]])
def get_menu_tree(
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
) -> Any:
    """获取菜单树形结构"""
    # 获取所有菜单
    menus = db.query(Menu).all()
    
    # 构建菜单树
    menu_tree = build_menu_tree(menus)
    
    return ResponseModel(data=menu_tree)

@router.get("", response_model=ResponseModel[PaginatedResponse[MenuSchema]])
def get_menus(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页数量"),
    name: Optional[str] = Query(None, description="菜单名称搜索"),
    parent_id: Optional[int] = Query(None, description="父菜单ID"),
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
) -> Any:
    """获取菜单列表"""
    query = db.query(Menu)
    
    if name:
        query = query.filter(Menu.name.contains(name))
    
    if parent_id is not None:
        query = query.filter(Menu.parent_id == parent_id)
    
    # 计算总数
    total = query.count()
    
    # 分页并排序
    menus = query.order_by(Menu.sort_order).offset((page - 1) * page_size).limit(page_size).all()
    
    return ResponseModel(
        data=PaginatedResponse(
            total=total,
            page=page,
            page_size=page_size,
            items=menus
        )
    )

@router.get("/{menu_id}", response_model=ResponseModel[MenuSchema])
def get_menu(
    menu_id: int,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
) -> Any:
    """获取菜单详情"""
    menu = db.query(Menu).filter(Menu.id == menu_id).first()
    if not menu:
        raise HTTPException(
            status_code=404,
            detail="菜单不存在"
        )
    
    return ResponseModel(data=menu)

@router.post("", response_model=ResponseModel[MenuSchema])
def create_menu(
    menu_in: MenuCreate,
    current_user: User = Depends(get_current_superuser),
    db: Session = Depends(get_db)
) -> Any:
    """创建菜单"""
    # 检查菜单名称是否已存在
    existing_menu = db.query(Menu).filter(Menu.name == menu_in.name).first()
    if existing_menu:
        raise HTTPException(
            status_code=400,
            detail="菜单名称已存在"
        )
    
    # 检查父菜单是否存在
    if menu_in.parent_id:
        parent_menu = db.query(Menu).filter(Menu.id == menu_in.parent_id).first()
        if not parent_menu:
            raise HTTPException(
                status_code=400,
                detail="父菜单不存在"
            )
    
    # 检查权限是否存在
    if menu_in.permission_ids:
        from models import Permission
        permissions = db.query(Permission).filter(Permission.id.in_(menu_in.permission_ids)).all()
        if len(permissions) != len(menu_in.permission_ids):
            raise HTTPException(
                status_code=400,
                detail="部分权限不存在"
            )
    
    # 创建菜单
    db_menu = Menu(**menu_in.dict())
    db.add(db_menu)
    db.commit()
    db.refresh(db_menu)
    
    return ResponseModel(data=db_menu)

@router.put("/{menu_id}", response_model=ResponseModel[MenuSchema])
def update_menu(
    menu_id: int,
    menu_in: MenuUpdate,
    current_user: User = Depends(get_current_superuser),
    db: Session = Depends(get_db)
) -> Any:
    """更新菜单"""
    menu = db.query(Menu).filter(Menu.id == menu_id).first()
    if not menu:
        raise HTTPException(
            status_code=404,
            detail="菜单不存在"
        )
    
    # 检查菜单名称是否已存在（排除当前菜单）
    if menu_in.name and menu_in.name != menu.name:
        existing_menu = db.query(Menu).filter(Menu.name == menu_in.name).first()
        if existing_menu:
            raise HTTPException(
                status_code=400,
                detail="菜单名称已存在"
            )
    
    # 检查父菜单是否存在
    if menu_in.parent_id is not None:
        if menu_in.parent_id == menu_id:
            raise HTTPException(
                status_code=400,
                detail="菜单不能作为自己的父菜单"
            )
        
        # 检查是否会造成循环引用
        def check_circular_reference(menu_id: int, parent_id: int) -> bool:
            """检查是否存在循环引用"""
            current = parent_id
            while current:
                m = db.query(Menu).filter(Menu.id == current).first()
                if not m:
                    return False
                if m.parent_id == menu_id:
                    return True
                current = m.parent_id
            return False
        
        if menu_in.parent_id:
            if check_circular_reference(menu_id, menu_in.parent_id):
                raise HTTPException(
                    status_code=400,
                    detail="设置父菜单会导致循环引用"
                )
            
            parent_menu = db.query(Menu).filter(Menu.id == menu_in.parent_id).first()
            if not parent_menu:
                raise HTTPException(
                    status_code=400,
                    detail="父菜单不存在"
                )
    
    # 检查权限是否存在
    if menu_in.permission_ids is not None:
        if menu_in.permission_ids:
            from models import Permission
            permissions = db.query(Permission).filter(Permission.id.in_(menu_in.permission_ids)).all()
            if len(permissions) != len(menu_in.permission_ids):
                raise HTTPException(
                    status_code=400,
                    detail="部分权限不存在"
                )
    
    # 更新字段
    update_data = menu_in.dict(exclude_unset=True)
    for field, value in update_data.items():
        setattr(menu, field, value)
    
    db.commit()
    db.refresh(menu)
    
    return ResponseModel(data=menu)

@router.delete("/{menu_id}", response_model=ResponseModel[dict])
def delete_menu(
    menu_id: int,
    current_user: User = Depends(get_current_superuser),
    db: Session = Depends(get_db)
) -> Any:
    """删除菜单"""
    menu = db.query(Menu).filter(Menu.id == menu_id).first()
    if not menu:
        raise HTTPException(
            status_code=404,
            detail="菜单不存在"
        )
    
    # 检查是否有子菜单
    child_menus = db.query(Menu).filter(Menu.parent_id == menu_id).count()
    if child_menus > 0:
        raise HTTPException(
            status_code=400,
            detail=f"该菜单下有{child_menus}个子菜单，无法删除"
        )
    
    # 检查菜单是否被角色使用
    from models import Role
    roles = db.query(Role).filter(Role.menu_ids.contains([menu_id])).count()
    if roles > 0:
        raise HTTPException(
            status_code=400,
            detail="该菜单已被角色使用，无法删除"
        )
    
    db.delete(menu)
    db.commit()
    
    return ResponseModel(data={"message": "菜单删除成功"})

@router.get("/user/menus", response_model=ResponseModel[List[MenuSchema]])
def get_user_menus(
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
) -> Any:
    """获取当前用户的菜单权限"""
    # 获取用户拥有的权限
    user_permissions = set()
    for role in current_user.roles:
        for permission in role.permissions:
            user_permissions.add(permission.id)
    
    # 获取所有菜单
    all_menus = db.query(Menu).filter(Menu.hidden == False).all()
    
    # 过滤用户有权限的菜单
    accessible_menus = []
    for menu in all_menus:
        # 如果菜单没有权限要求，或者用户拥有菜单要求的权限，则可访问
        if not menu.permission_ids or any(pid in user_permissions for pid in menu.permission_ids):
            accessible_menus.append(menu)
    
    # 构建菜单树
    menu_tree = build_menu_tree(accessible_menus)
    
    return ResponseModel(data=menu_tree)